require "classes/hero"
require "classes/knife"
require "classes/enemy"

stage = {
  map = {},
  tileX = 90,
  tileY = 95,
  -- Tile Variables
  tile_ground = love.graphics.newImage("images/stage1/90x95/squareground.png"),
  tile_wall = love.graphics.newImage("images/stage1/90x95/wall.png"),
  tile_door = love.graphics.newImage("images/stage1/90x95/squarejaildoor.png"),
  tile_open_cell = love.graphics.newImage("images/stage1/90x95/open_cell.png"),
  tile_window = love.graphics.newImage("images/stage1/90x95/window.png"),
  tile_exit = love.graphics.newImage("images/stage1/90x95/exitdoor.png"),
  -- Camera Variables
  offset_x = 0,
  first_tile_x = 0,
  hero = hero,
  enemy = enemy,
  knife = knife,
  stageState = "playing",

  camera = {
    pos_x = 1,
    pos_y = 1,
    speed = 200,
    totalx = 0,
    totaly = 0,
  },
  
  exit = {
    pos_x = 542,
    pos_y = 380,
    image = love.graphics.newImage("images/stage1/90x95/exitdoor.png"),
    height = 90,
    width = 95,
    
    
    playerAtExit = function()
      return stage.hero.x > stage.exit.pos_x 
         and stage.hero.y > stage.exit.pos_y 
         and stage.hero.x < stage.exit.pos_x + stage.exit.width 
         and stage.hero.y < stage.exit.pos_y + stage.exit.height
    end
  },
  
  isHeroNearDoor = function(doorLetter)
    local i = math.floor(stage.hero.y / stage.tileY) --estatico
    local j = math.floor((stage.hero.x + 40) / stage.tileX)

    return (stage.map[i][j] == doorLetter)
  end,
 
  isHeroFacingEnemy = function()
    if (stage.hero.hidden == false) then
      if (stage.enemy.direction == 3) then
        return (stage.enemy.x - stage.hero.x) > 0
      elseif (stage.enemy.direction == 1) then
        return (stage.enemy.x - stage.hero.x) < 0
      end
    end
    return false
  end,
  
  map_config = {
    mapSize_x = 25,
    mapSize_y = 6,
    mapDisplay_x = 10,
    mapDisplay_y = 6
  },

  loadMap = function(filename)
    local file = io.open(filename)
    local i = 1
    for line in file:lines() do
      stage.map[i] = {}
      for j=1, #line, 1 do
        stage.map[i][j] = line:sub(j,j)
      end
      i = i + 1
    end
    file:close()
  end,

  drawMap = function()
    stage.offset_x = math.floor(stage.camera.pos_x % stage.tileX)
    stage.first_tile_x = math.floor(stage.camera.pos_x / stage.tileX) 
    for i=1, stage.map_config.mapDisplay_y, 1 do
      for j=1, stage.map_config.mapDisplay_x, 1 do
        if (stage.map[i][stage.first_tile_x + j] == "G") then
          love.graphics.draw(stage.tile_ground,((j-1) * stage.tileX) - stage.offset_x, ((i-1) * stage.tileY))
        elseif (stage.map[i][stage.first_tile_x + j] == "D") then
          love.graphics.draw(stage.tile_open_cell,((j-1) * stage.tileX) - stage.offset_x, ((i-1) * stage.tileY))
        elseif (stage.map[i][stage.first_tile_x + j] == "X") then
          love.graphics.draw(stage.tile_wall,((j-1) * stage.tileX) - stage.offset_x, ((i-1) * stage.tileY))
        elseif (stage.map[i][stage.first_tile_x + j] == "W") then
          love.graphics.draw(stage.tile_window,((j-1) * stage.tileX) - stage.offset_x, ((i-1) * stage.tileY))
        elseif (stage.map[i][stage.first_tile_x + j] == "E") then
          love.graphics.draw(stage.tile_exit,((j-1) * stage.tileX) - stage.offset_x, ((i-1) * stage.tileY))
        end
      end
    end 
  end
}

function stage:load()
  -- Adjusting Screen Size for the Game
  -- Shows only 8 tile of length 
  love.window.setMode( stage.tileX*8, stage.tileY*stage.map_config.mapDisplay_y)
  stage.loadMap("maps/stage1.txt")
  stage.hero.loadImage()
  stage.hero.loadImageHidden()
  knife.loadImage()
  enemy.loadImage()
  stage.enemy.move("right", 0)
  stage.stageState = "playing"
end

function stage:draw()
  -- Drawing the Map
  stage.drawMap()
  
  -- Drawing Hero
  -- If hidden show hero image darkened, if not normal image
  if(hero.hidden) then
    love.graphics.draw(stage.hero.charImageHidden, stage.hero.charQuadsHidden[stage.hero.direction][stage.hero.frame], stage.hero.x, stage.hero.y, 0, 1, 1, stage.hero.spriteX, stage.hero.spriteY)
  else
    love.graphics.draw(stage.hero.charImage, stage.hero.charQuads[stage.hero.direction][stage.hero.frame], stage.hero.x, stage.hero.y, 0, 1, 1, stage.hero.spriteX, stage.hero.spriteY)
  end
  
  love.graphics.draw(stage.enemy.charImage, stage.enemy.charQuads[stage.enemy.direction][stage.enemy.frame], stage.enemy.x, stage.enemy.y, 0, 1, 1, stage.enemy.spriteX, stage.enemy.spriteY)
  
  -- Drawing knifes
  for i,v in ipairs(hero.knifes) do
    --love.graphics.circle("fill", v.x, v.y, 3)
    love.graphics.draw(v.charImage, v.charQuads[v.direction], v.x, v.y, 0, 1, 1, v.spriteX, v.spriteY)
  end

end

function stage:update(dt)

    -- If the player is found the game ends
  if stage.isHeroFacingEnemy() then
    stage.stageState = "terminated"
  end

  if love.keyboard.isDown("up") then 
      -- Check if hero is at the exit
    if stage.isHeroNearDoor("E") then
      stage.stageState = "completed"
    else
      stage.hero.hidden = stage.isHeroNearDoor("D")
    end
    if (stage.hero.hidden) then
      stage.hero.direction = 2
    else
      stage.hero.move("up", dt)
    end
    
  elseif love.keyboard.isDown("down") then 
    stage.hero.hidden = false
    stage.hero.move("down", dt)   
  elseif love.keyboard.isDown("left") then 
    stage.hero.hidden = false
    stage.hero.move("left", dt)     
    --stage.camera.pos_x = stage.camera.pos_x - (stage.camera.speed * dt)
  elseif love.keyboard.isDown("right") then 
    stage.hero.hidden = false
    stage.hero.move("right", dt)
    --stage.camera.pos_x = stage.camera.pos_x + (stage.camera.speed * dt)
  end
  
  --drop enemy to the ground
  stage.enemy.updateGround(dt)
  --animate enemy
  if (stage.enemy.x > 650) then
    stage.enemy.move("left", dt)
  elseif (stage.enemy.x > 70 and stage.enemy.direction == 3) then
    stage.enemy.move("left", dt)
  elseif (stage.enemy.x > 70 and stage.enemy.direction == 1) then
    stage.enemy.move("right", dt)
  elseif (stage.enemy.x < 70) then
    stage.enemy.move("right", dt)
  end
  
  -- Jumping Part
  stage.hero.updateGround(dt)
  stage.hero.checkJump(dt)
  -- Boost Part
  stage.hero.checkVelocity(dt)

  --Updating Knifes
  for i,v in ipairs(hero.knifes) do
    v.x = v.x + (v.dx * dt)
    v.y = v.y + (v.dy * dt)
  end

  -- Camera Movement
  if stage.camera.pos_x < 0 then
    stage.camera.pos_x = 0
  elseif stage.camera.pos_x > stage.map_config.mapSize_x * stage.tileX - stage.map_config.mapDisplay_x * stage.tileX - 1 then
    stage.camera.pos_x = stage.map_config.mapSize_x * stage.tileX - stage.map_config.mapDisplay_x * stage.tileX - 1
  end 

end

function stage:reset()
  stage.camera = {
    pos_x = 1,
    pos_y = 1,
    speed = 200
  }
  stage.tileX = 90
  stage.tileY = 95
  stage.offset_x = 0
  stage.first_tile_x = 0
  stage.hero.direction = 2 -- Frontal Direction
  stage.hero.x = stage.hero.initialX
  stage.hero.y = love.graphics.getHeight() -95 - (96/2)
  
  stage.enemy.direction = 2 -- Frontal Direction
  stage.enemy.x = stage.enemy.initialX
  stage.enemy.y = love.graphics.getHeight() -95 - (96/2)
  stage.enemy.move("right", 0)
  stage.stageState = "playing"
end

function stage:keypressed( key )
  --Jump
  if key == "z" and stage.hero.jump == false and 
  stage.hero.y > love.window.getHeight() - 95 then -- So player does not fly from multiple fast jumps
    stage.hero.jump = true
  end
  --Boost
  if key == "lshift" and stage.hero.jump == false then
    stage.hero.boost = true
  end
  
  --Fire Knife, only when player os looking left or right
  if key == " " and (hero.direction == 1 or hero.direction == 3) then
    local startX = stage.hero.x - 25 -- Minus 25 to be in the middle of the player
    local startY = stage.hero.y - 25 -- Minus 25 to be in the middle of the player

    kf = stage.knife:GetInstance()

    -- Getting knife direction by player direction
    local dir
    if(stage.hero.direction == 1) then -- Right
      dir = 1 
      kf.direction = 1
    elseif(stage.hero.direction == 3) then  -- Left
      dir = -1 
      kf.direction = 0
    end

    local angle = math.atan2((0), (dir * startX))
    local knifeDx = kf.speed * math.cos(angle)
    local knifeDy = kf.speed * math.sin(angle)

    kf.x = startX
    kf.y = startY
    kf.dx = knifeDx
    kf.dy = knifeDy

    table.insert(stage.hero.knifes, kf)
  end

end